<?php
/**
 * Created by PhpStorm.
 * Script Name: Base.php
 * Create: 2023/5/25 8:31
 * Description:
 * Author: fudaoji<fdj@kuryun.cn>
 */

namespace addons\fhelper\admin\controller;

use addons\fhelper\common\library\FmConfig;
use app\addon\AddonAdminController;

class Base extends AddonAdminController
{
    protected $files = [];
    protected $folders = [];
    protected $path;
    protected $lang = 'zh-CN';
    protected $configs = [];

    public function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub
        $this->configs = FmConfig::getConf();

        // max upload file size
        define('MAX_UPLOAD_SIZE', $this->configs['max_upload_size']);

        // upload chunk size
        define('UPLOAD_CHUNK_SIZE', $this->configs['upload_chunk_size']);

        // private key and session name to store to the session
        if ( !defined( 'FM_SESSION_ID')) {
            define('FM_SESSION_ID', 'filemanager');
        }
        // input encoding for iconv
        $iconv_input_encoding = 'UTF-8';
        defined('FM_ICONV_INPUT_ENC') || define('FM_ICONV_INPUT_ENC', $iconv_input_encoding);

        // --- EDIT BELOW CONFIGURATION CAREFULLY ---
        // Auth with login/password
        // set true/false to enable/disable it
        // Is independent from IP white- and blacklisting
        $use_auth = true;
        // Login user name and password
        // Users: array('Username' => 'Password', 'Username2' => 'Password2', ...)
        // Generate secure password hash - https://tinyfilemanager.github.io/docs/pwd.html
        $auth_users = [];
        // Readonly users
        // e.g. array('users', 'guest', ...)
        $readonly_users = ['user'];
        // Global readonly, including when auth is not being used
        $global_readonly = false;
        // user specific directories
        // array('Username' => 'Directory path', 'Username2' => 'Directory path', ...)
        $directories_users = [];


        // Files and folders to excluded from listing 排除哪些文件
        // e.g. array('myfile.html', 'personal-folder', '*.php', ...)
        defined('FM_EXCLUDE_ITEMS') || define('FM_EXCLUDE_ITEMS', (version_compare(PHP_VERSION, '7.0.0', '<') ? serialize($this->configs['exclude_items']) : $this->configs['exclude_items']));

        // Root path for file manager
        // use absolute path of directory i.e: '/var/www/folder' or $_SERVER['DOCUMENT_ROOT'].'/folder'
        $root_path = $this->configs['root_path']; //$_SERVER['DOCUMENT_ROOT'];

        // Root url for links in file manager.Relative to $http_host. Variants: '', 'path/to/subfolder'
        // Will not working if $root_path will be outside of server document root
        $root_url = $this->configs['root_url'];

        // Server hostname. Can set manually if wrong
        // $_SERVER['HTTP_HOST'].'/folder'
        $http_host = $_SERVER['HTTP_HOST'];

        // date() format for file modification date
        // Doc - https://www.php.net/manual/en/function.date.php
        $datetime_format = $this->configs['date_format'];

        // Path display mode when viewing file information
        // 'full' => show full path
        // 'relative' => show path relative to root_path
        // 'host' => show path on the host
        $path_display_mode = $this->configs['path_display_mode'];

        // Sticky Nav bar 是否固定顶部导航
        // true => enable sticky header
        // false => disable sticky header
        $sticky_navbar = $this->configs['sticky_navbar'];

        // Default language
        $lang = $this->lang = $this->configs['lang'];

        // Show or hide files and folders that starts with a dot
        $show_hidden_files = $this->configs['show_hidden'];

        // PHP error reporting - false = Turns off Errors, true = Turns on Errors
        $report_errors = $this->configs['error_reporting'];

        // Hide Permissions and Owner cols in file-listing
        $hide_Cols = $this->configs['hide_Cols'];

        // Theme
        $theme = $this->configs['theme'];
        define('FM_THEME', $theme);

        if ($report_errors == true) {
            @ini_set('error_reporting', E_ALL);
            @ini_set('display_errors', 1);
        } else {
            @ini_set('error_reporting', E_ALL);
            @ini_set('display_errors', 0);
        }

        // if fm included
        if (defined('FM_EMBED')) {
            $use_auth = false;
            $sticky_navbar = false;
        } else {
            @set_time_limit(600);
            $default_timezone = 'Etc/UTC'; // UTC
            date_default_timezone_set($default_timezone);
            ini_set('default_charset', 'UTF-8');
            if (version_compare(PHP_VERSION, '5.6.0', '<') && function_exists('mb_internal_encoding')) {
                mb_internal_encoding('UTF-8');
            }
            if (function_exists('mb_regex_encoding')) {
                mb_regex_encoding('UTF-8');
            }
            session_cache_limiter('nocache'); // Prevent logout issue after page was cached
            session_name(FM_SESSION_ID);
            set_error_handler('session_error_handling_function');
            session_start();
            restore_error_handler();
        }

        if (empty($auth_users)) {
            $use_auth = false;
        }

        $is_https = isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1)
            || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https';

        // update $root_url based on user specific directories
        if (isset(session('FM_SESSION_ID')['logged']) && !empty($directories_users[session('FM_SESSION_ID')['logged']])) {
            $wd = fm_clean_path(dirname($_SERVER['PHP_SELF']));
            $root_url = $root_url . $wd . DIRECTORY_SEPARATOR . $directories_users[session('FM_SESSION_ID')['logged']];
        }
        // clean $root_url
        $root_url = fm_clean_path($root_url);

        // abs path for site
        defined('FM_ROOT_URL') || define('FM_ROOT_URL', ($is_https ? 'https' : 'http') . '://' . $http_host . (!empty($root_url) ? '/' . $root_url : ''));
        defined('FM_SELF_URL') || define('FM_SELF_URL', ($is_https ? 'https' : 'http') . '://' . $http_host . $this->request->request('s'));

        $this->validateIp();

        // clean and check $root_path
        $root_path = rtrim($root_path, '\\/');
        $root_path = str_replace('\\', '/', $root_path);
        if (!@is_dir($root_path)) {
            echo "<h1>" . lng('Root path') . " \"{$root_path}\" " . lng('not found!') . " </h1>";
            exit;
        }

        defined('FM_SHOW_HIDDEN') || define('FM_SHOW_HIDDEN', $show_hidden_files);
        defined('FM_ROOT_PATH') || define('FM_ROOT_PATH', $root_path);
        defined('FM_LANG') || define('FM_LANG', $lang);

        define('FM_READONLY', $global_readonly || ($use_auth && !empty($readonly_users) && isset(session('FM_SESSION_ID')['logged']) && in_array(session('FM_SESSION_ID')['logged'], $readonly_users)));
        define('FM_IS_WIN', DIRECTORY_SEPARATOR == '\\');

        // for ajax request - save
        $input = input();
        // get path
        $p = fm_clean_path(input('p', ''));
        // get parent folder
        $parent = fm_get_parent_path($p);

        // instead globals vars
        define('FM_PATH', $p);
        define('FM_USE_AUTH', $use_auth);


        defined('FM_DATETIME_FORMAT') || define('FM_DATETIME_FORMAT', $datetime_format);
        unset($p, $use_auth, $use_highlightjs, $highlightjs_style);

        $path = FM_ROOT_PATH;
        if (FM_PATH != '') {
            $path .= '/' . FM_PATH;
        }
        $objects = is_readable($path) ? scandir($path) : [];
        $current_path = array_slice(explode("/", $path), -1)[0];
        $files = [];
        $folders = [];
        if (is_array($objects) && fm_is_exclude_items($current_path)) {
            foreach ($objects as $file) {
                if ($file == '.' || $file == '..') {
                    continue;
                }
                if (!FM_SHOW_HIDDEN && substr($file, 0, 1) === '.') {
                    continue;
                }
                $new_path = $path . '/' . $file;
                if (@is_file($new_path) && fm_is_exclude_items($file)) {
                    $files[] = $file;
                } elseif (@is_dir($new_path) && $file != '.' && $file != '..' && fm_is_exclude_items($file)) {
                    $folders[] = $file;
                }
            }
        }

        if (!empty($files)) {
            natcasesort($files);
        }
        if (!empty($folders)) {
            natcasesort($folders);
        }
        $this->files = $files;
        $this->folders = $folders;
        $this->path = $path;

        if(input('type', '') == 'search'){ //高级搜索
            $dir = input('post.path', '') == "." ? '': input('post.path', '');
            $response = scan(fm_clean_path($dir), input('post.content', ''));
            echo(json_encode($response));exit;
        }

        $isStickyNavBar = $sticky_navbar ? 'navbar-fixed' : 'navbar-normal';
        $this->assign = compact(
            "isStickyNavBar", "root_path", "root_url",
            'sticky_navbar', 'lang', 'hide_Cols', 'parent',
            'files', 'folders', 'current_path', 'path', 'report_errors', 'show_hidden_files'
        );
    }

    /**
     * 创建文件/文件夹
     * Author: fudaoji<fdj@kuryun.cn>
     */
    function createFile()
    {
        $check = $this->request->checkToken('__token__');
        if (false === $check) {
            $this->error("非法操作！");
        }
        $post_data = input('post.');
        if (!isset($post_data['newfilename'], $post_data['newfile'])) {
            $this->error("参数错误!");
        }

        $type = urldecode($post_data['newfile']);
        $new = str_replace('/', '', fm_clean_path(strip_tags($post_data['newfilename'])));
        if (fm_isvalid_filename($new) && $new != '' && $new != '..' && $new != '.') {
            $path = FM_ROOT_PATH;
            if (FM_PATH != '') {
                $path .= '/' . FM_PATH;
            }

            if ($type == "file") {
                if (!file_exists($path . '/' . $new)) {
                    if (fm_is_valid_ext($new)) {
                        @fopen($path . '/' . $new, 'w') or die('Cannot open file:  ' . $new);
                        $this->success(sprintf(lng('File') . ' <b>%s</b> ' . lng('Created'), fm_enc($new)));
                    } else {
                        $this->error(lng('File extension is not allowed'));
                    }
                } else {
                    $this->error(sprintf(lng('File') . ' <b>%s</b> ' . lng('already exists'), fm_enc($new)));
                }
            } else {
                if (fm_mkdir($path . '/' . $new, false) === true) {
                    $this->success(sprintf(lng('Folder') . ' <b>%s</b> ' . lng('Created'), $new));
                } elseif (fm_mkdir($path . '/' . $new, false) === $path . '/' . $new) {
                    $this->error(sprintf(lng('Folder') . ' <b>%s</b> ' . lng('already exists'), fm_enc($new)));
                } else {
                    $this->error(sprintf(lng('Folder') . ' <b>%s</b> ' . lng('not created'), fm_enc($new)));
                }
            }
        } else {
            $this->error(lng('Invalid characters in file or folder name'));
        }
    }

    /**
     * IP验证
     * Author: fudaoji<fdj@kuryun.cn>
     */
    private function validateIp()
    {
        // Possible rules are 'OFF', 'AND' or 'OR'
        // OFF => Don't check connection IP, defaults to OFF
        // AND => Connection must be on the whitelist, and not on the blacklist
        // OR => Connection must be on the whitelist, or not on the blacklist
        $ip_ruleset = $this->configs['ip_ruleset'];

        // Should users be notified of their block?
        $ip_silent = true;

        // IP-addresses, both ipv4 and ipv6
        $ip_whitelist = $this->configs['ip_whitelist'];

        // IP-addresses, both ipv4 and ipv6
        $ip_blacklist = $this->configs['ip_blacklist'];

        // Validate connection IP
        if ($ip_ruleset != 'OFF') {
            $clientIp = fhelper_get_client_ip();
            $proceed = false;
            $whitelisted = in_array($clientIp, $ip_whitelist);
            $blacklisted = in_array($clientIp, $ip_blacklist);

            if ($ip_ruleset == 'AND') {
                if ($whitelisted == true && $blacklisted == false) {
                    $proceed = true;
                }
            } else if ($ip_ruleset == 'OR') {
                if ($whitelisted == true || $blacklisted == false) {
                    $proceed = true;
                }
            }

            if ($proceed == false) {
                trigger_error('User connection denied from: ' . $clientIp, E_USER_WARNING);
                if ($ip_silent == false) {
                    exit(lng('Access denied. IP restriction applicable'));
                }
            }
        }
    }
}